#include "TSS_Action.h"

/**
  * @brief  动作播放模块
  * @note   自行创建动作结构体数组TSS_ActionTableDef
  *         结构体内每一组代表一个动作节点
  *         每个动作节点由四部分组成:
  *         1.起始函数，这个函数在动作节点一开始被执行一次，可为NULL
  *         2.运行函数，这个函数在动作执行期间被不断执行，可为NULL，可设置执行周期
  *         3.条件函数，这个函数为动作的结束条件，可为NULL
  *         4.结束函数，这个函数在动作节点结束的时候被执行一次，可为NULL
  *         通过自由地修改函数，可自由地编写动作
  *         参数可为任意的类型，强制类型转换即可
  *         例子:
  *         TSS_ActionTableDef ActionExcmple[] = {
                {Action_ExcmpleStart, Action_ExcmpleRun, 50, Action_ExcmpleCondition, Action_ExcmpleEnd, NULL},
                ......
                ......
            };
            uint16_t ActionExcmpleLen = sizeof(ActionExcmple) / sizeof(TSS_ActionTableDef);
  */
static uint8_t TSS_ACTIONTASK_ID = 0;
static void TSS_ActionTask(TSS_TaskMessageDef *p)
{
    TSS_ActionPlayerDef *Action = (TSS_ActionPlayerDef *)p->data;

    if (Action->status != TSS_ACTION_BLOCK)
    {
        uint16_t node = Action->play_node;
        void *parameter = Action->table[node].parameter;
        switch (Action->status)
        {
        case TSS_ACTION_START:
            if (Action->table[node].start_fun != NULL)
            {
                Action->table[node].start_fun(parameter);
            }
            Action->status = TSS_ACTION_RUN;
            break;
        case TSS_ACTION_RUN:
            if (Action->table[node].condition_fun != NULL)
            {
                int8_t condition = Action->table[node].condition_fun(parameter);
                if (condition == TSS_ACTIONFUN_OK)
                {
                    if (TSS_GetRunTime() - Action->play_time > Action->table[node].cycle)
                    {
                        Action->play_time = TSS_GetRunTime();
                        Action->table[node].run_fun(parameter);
                    }
                }
                else if (condition == TSS_ACTIONFUN_END)
                {
                    Action->status = TSS_ACTION_END;
                }
            }
            else
            {
                Action->status = TSS_ACTION_END;
            }
            break;
        case TSS_ACTION_END:
            if (Action->table[node].end_fun != NULL)
            {
                Action->table[node].end_fun(parameter);
            }
            Action->status = TSS_ACTION_START;

            //动作播放结束
            Action->play_node++;
            if (Action->play_node >= Action->play_len)
            {
                Action->times--;
                if (Action->times == 0)
                {
                    Action->status = TSS_ACTION_BLOCK;
                }
                else
                {
                    Action->play_node = 0;
                    Action->play_time = 0;
                    Action->status = TSS_ACTION_START;
                }
            }
            break;
        default:
            break;
        }
    }
}

/**
  * @brief  创建一个动作模块
  * @param  Action        动作状态结构体
  * @param  priority      优先级
  * @retval 返回动作模块ID
  * @note   一个动作模块同时只能播放一个动作
  *         多个动作同时播放时, 需要创建多个动作模块
  */
uint8_t TSS_ActionCreate(TSS_ActionPlayerDef *Action, uint8_t Priority)
{
    TSS_ACTIONTASK_ID = TSS_ThreadCreate(TSS_ActionTask, Priority, TASK_HZ, 10);
    TSS_TaskMessageDef Message = {0};
    Message.data = (void *)Action;
    TSS_ThreadPutMessage(TSS_ACTIONTASK_ID, Message);
    return TSS_ACTIONTASK_ID;
}

/**
  * @brief  启动一个动作组
  * @param  Action      动作状态结构体
  * @param  Table       动作列表
  * @param  Len         动作列表的步数
  * @param  Times       动作的循环次数, ACTION_TIMEMAX为无限循环
  * @retval 返回成功或者失败
  * @note   无
  */
int8_t TSS_ActionStart(TSS_ActionPlayerDef *Action, TSS_ActionTableDef *Table, uint16_t Len, uint32_t Times)
{
    if (Times == 0)
        Times = 1;
    if (Action->status == TSS_ACTION_BLOCK)
    {
        memset((void *)Action, 0, sizeof(TSS_ActionPlayerDef));
        Action->table = Table;
        Action->play_len = Len;
        Action->status = TSS_ACTION_START;
        Action->times = Times;
        return TSS_OK;
    }
    return TSS_ERROR;
}

/**
  * @brief  结束一个动作组
  * @param  Action      动作状态结构体
  * @retval 无
  * @note   无
  */
void TSS_ActionStop(TSS_ActionPlayerDef *Action)
{
    Action->play_node = 0;
    Action->play_time = 0;
    Action->status = TSS_ACTION_BLOCK;
}
